package dht.entity;

import dht.IEntity;
import dse.modules.eln.GeometryUtil;

public class NodeInfo implements IEntity, Cloneable {

	private static final long serialVersionUID = 1L;
	private String ip;
	private int port;
	private double x;
	private double y;

	@Override
	public synchronized Object clone() {
		try {
			NodeInfo m = (NodeInfo) super.clone();
			return m;
		} catch (CloneNotSupportedException e) {
			throw new InternalError();
		}
	}

	public String getServerId() {
		return getServerId(ip, port);
	}

	public static String getServerId(String ip, int port) {
		return ip + ":" + port;
	}

	public String getIp() {
		return ip;
	}

	public void setIp(String ip) {
		this.ip = ip;
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	@Override
	public boolean equals(Object obj) {
		NodeInfo serverInfo = (NodeInfo) obj;
		if (serverInfo != null && ip.equals(serverInfo.getIp())
				&& port == serverInfo.getPort()) {
			return true;
		}
		return false;
	}

	@Override
	public int hashCode() {
		return ip.hashCode() ^ new Integer(port).hashCode();
	}

	public double getX() {
		return x;
	}

	public void setX(double x) {
		this.x = x;
	}

	public double getY() {
		return y;
	}

	public void setY(double y) {
		this.y = y;
	}

	public double distanceTo(NodeInfo other) {
		return distance(this, other);
	}

	public double cost(NodeInfo to, long size) {
		return cost(this, to, size);
	}

	public static double distance(NodeInfo from, NodeInfo to) {
		double distance = GeometryUtil.distance(from.getX(), from.getY(),
				to.getX(), to.getY());
		// if (distance == 0)
		// return 0.1;
		return distance;
	}

	public static double cost(NodeInfo from, NodeInfo to, long size) {
		double distance = distance(from, to);
		// double pingCostInMS = 0.5 + 0.18*Math.pow(distance, 0.74);
		// double latency = (0.05*Math.pow(size, 0.46)*pingCostInMS +
		// pingCostInMS)/1000;
		// double mu = 1.0/0.3;
		// double sign = Math.random()<0.5?-1:1;
		// double error = -Math.log(1-Math.random())/mu;
		double pingCostInMS = 0.4 + 0.3 * Math.pow(distance, 0.735);
		double latency = (0.02 * Math.pow(size, 0.51) * pingCostInMS + pingCostInMS) / 1000;
		// double mu = 1.0/0.3;
		// double sign = Math.random()<0.5?-1:1;
		// double error = -Math.log(1-Math.random())/mu;
		return latency;// + latency*sign*error;
	}

}
